<template>
    <h4>组合式API语法 -【hook】- 钩子函数</h4>
    <p>
        1. ref 函数用于构建响应式数据(提供的数据值将被作为一个空对象的value进行存储，在完成响应构建)<br>
            + ref 会自行完成一个独立的vue响应式对象定义<br>
            + 并将接收的参数作为该数据的默认值写在对象的value属性上<br>
            + ref 构建的响应式对象变量，在vue模板语法中会自动调用value属性<br>
            + js 代码中如果需要获取数据，必须对ref构建的响应式变量调用 value 属性<br>
        2. reactive 函数用于构建响应式数据(直接将提供的数据对象构建成响应式)
    </p>
    <p>3. 在组合式API 定义的普通方法就是仓库方法( 此时方法中的this是基于组合式API构建数据组成的一个独立的特殊对象=不是vue实例对象 )</p>
    <p>msg:{{ msg }}</p>
    <input v-model="msg" type="text" />
    <input type="button" value="printMsg" @click="printMsg()">
    <p>user:{{ user }}</p>
    <input v-model="user.name" type="text" />
    <input type="button" value="printUser" @click="printUser()">
    <p>obj:{{ obj }}</p>
    <input v-model="obj.info" type="text" />
    <input type="button" value="printInfo" @click="printInfo()">

    <p>4. computed函数用于构建计算属性变量，使用规则和定义规则等同于选项式的规则</p>
    <p>text:{{ text }}</p>
    <input v-model="text" type="text" />
    <p>compText:{{ compText }}</p>
    <input v-model="compText" type="text" />
    <p>desc:{{ desc }}</p>
    <input v-model="desc" type="text" />
    <p>compDesc:{{ compDesc }}</p>
    <input v-model="compDesc" type="text" />
    
    <p>5. watch 函数用于构建对应的监视方法，使用规则和定义规则等同于实例方法$watch</p>
    <p>str:{{ str }}</p>
    <input v-model="str" type="text" />
    <input type="button" value="关键监视器" @click="unStrWatch()" />

    <p>
        6. ref 函数的元素指向型用法 <br>
        + 当ref对应的声明名称，和模板中具有ref属性的标签的取值名称相同时，ref用于加载对应元素
    </p>
    <p ref="pDom">pDom元素</p>
    <input type="button" value="打印pDom元素" @click="printPDom()">

    <p>
        7. defineProps 方法用于构建父向子数据传递时的拦截器，定义规则和使用方法等同于props属性
        + defineProps 不用导入直接可以使用【仅限于vite】
    </p>
    <p>username:{{ username }}</p>
    <input type="button" value="printUsername" @click="printUsername()">

    <p>
        8. defineEmits 方法用于构建子向父数据传递时的事件拦截器，定义规则emits属性
        + defineEmits 不用导入直接可以使用【仅限于vite】
    </p>
    <input type="button" value="执行父组件事件" @click="execParentCallback()">

    <p>
        9. defineExpose 方法用于定义组件可以直接多外公开的属性或者方法
        + defineExpose 不用导入直接可以使用【仅限于vite】
        + 选项式api无效声明和描述，组件本身的所有属性和方法都会对外公开
        + 组合式api只用被 defineExpose 描述的属性或者方法才会对外公开
    </p>

    <p>
        10. 生命周期钩子函数
        + 没有 beforeCreate 和 created 函数
        + 因为响应数据的定义是通过ref方法手动构建的，所以只要保证代码定义顺序，初始化调用只需要直接完成方法执行即可
        + 组合式生命周期函数通过vue提供对立调用方法执行，列如 mounted 钩子函数在组合式api中需要通过 onMounted(callback) 完成定义
    </p>

    <p>
        11. 插件的组合式api
        + 官方建议，为vue3组合式api提供相关支持语法的插件，建议以 use名称 方式构成组合式调用方法，提供组合式语法支持
    </p>

    <p>
        12. 组件定义规则
        + 选项式或者组合选项混合式，组件的导入和定义规则不发生任何变化
        + 单组合式环境下，组件导入即为定义
    </p>
    <CompTest></CompTest>
</template>

<script setup>
import { ref,reactive,computed,watch,defineProps,defineEmits,defineExpose,onMounted } from "vue";
import CompTest from "./CompTest.vue";

import { useRoute,useRouter } from "vue-router";
const $route = useRoute(); // 加载路由信息对象
const $router = useRouter(); // 加载路由控制对象
console.log("路由信息对象",$route);
console.log("路由信息对象path",$route.path);
console.log("路由实例[控制]对象",$router);


let msg = ref("测试数据"); // ==> { value:"测试数据" }
// console.log(msg);
function printMsg(){
    console.log("msg:",msg);
    console.log("msg.value:",msg.value);
}

let user = ref({ name:"tom",age:23 })
// console.log(user);
const printUser = function(){
    console.log("user:",user);
    console.log("user.value:",user.value);
}

let obj = reactive({
    info:"info响应数据",
    arr:[1,2,3,4,5]
})
// console.log(obj);
// console.log(obj.info);
const printInfo = function(){
    console.log("obj.info:",obj.info);
}

let text = ref("text变量")
let compText = computed(function(){
    // 构建只读计算属性
    return text.value + ".end"
})

let desc = ref("desc变量")
let compDesc = computed({
    // 构建可读可写的计算属性
    get(){
        return desc.value + ".end"
    },
    set(nv){
        desc.value = nv;
    }
})

let str = ref("ref变量")
// 组合式API watch 函数的使用规则等同于实例方法 $watch
//      第一个参数如果是变量需要直接定义响应式变量对象
// let unStrWatch = watch(str,function(nv,ov){
//     console.log("str.value 发生修改:",nv,ov);
// }) 
let unStrWatch = watch(
    function(){
        return str.value
    },
    function(nv,ov){
        console.log("str.value 发生修改:",nv,ov);
    },
    {
        // deep:true,
        immediate:true
    }
) 

let pDom = ref();
const printPDom = function(){
    // console.log(this);
    // console.log(this.$refs);
    console.log(pDom.value);
}


const props = defineProps(["username"])
// defineProps({
//     username:{
//         type:String,
//         default:"默认值"
//     }
// })
const printUsername = function(){
    console.log(props);
    console.log(props.username);
}

const emit = defineEmits(["exec"])
const execParentCallback = function(){
    emit("exec","参数")
}

onMounted(function(){
    console.log("vue实例挂载完成后的执行方法");
})


defineExpose({
    msg,
    printMsg
})
</script>

<style lang="scss" scoped>

</style>